/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.dialog.schema.model;

import offset.nodes.client.model.AbstractSchemaTree;
import offset.nodes.client.virtual.model.SchemaItem;
import offset.nodes.client.virtual.model.SchemaNode;
import offset.nodes.client.virtual.model.SchemaProperty;
import offset.nodes.client.model.NodeTypes;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import offset.nodes.client.virtual.model.jcr.nodetype.NodeDefinition;
import offset.nodes.client.virtual.model.jcr.nodetype.NodeTypeDefinition;
import offset.nodes.client.virtual.model.jcr.nodetype.PropertyDefinition;

/**
 * Implements the model of a flat schema tree.
 *
 * Such a tree will have all types as children of root. The types themselves will have only
 * a single level of child nodes and properties.
 * @author Walter Lütgenau
 */
public class FlatTree extends AbstractSchemaTree {
    
    /** Creates a new instance of FlatTree */
    public FlatTree(JTree tree) {
        this.setTree(tree);
        this.setRoot((DefaultMutableTreeNode) ((DefaultTreeModel)tree.getModel()).getRoot());
    }
    
    
    public void removeType(DefaultMutableTreeNode node) {
        if( !(node.getUserObject() instanceof SchemaNode) || ((SchemaNode)node.getUserObject()).getNodeType() == null )
            return; // remove types only
        
        NodeTypeDefinition type = ((SchemaNode)node.getUserObject()).getNodeType();
        
        for( int i=0; i<getRoot().getChildCount(); i++) {
            DefaultMutableTreeNode child = (DefaultMutableTreeNode) getRoot().getChildAt(i);
            if ( hasType(child, type)) {
                ((DefaultTreeModel) getTree().getModel()).removeNodeFromParent(child);
                return;
            }
        }
    }
    
    public void removeChildFromType(DefaultMutableTreeNode parent, DefaultMutableTreeNode child) {
        if( !(parent.getUserObject() instanceof SchemaNode) || ((SchemaNode)parent.getUserObject()).getNodeType() == null )
            return; // remove types only
        if ( !(child.getUserObject() instanceof SchemaItem))
            return; // insert schema items only
        
        NodeTypeDefinition type = ((SchemaNode)parent.getUserObject()).getNodeType();
        SchemaItem item = (SchemaItem) child.getUserObject();
        
        for( int i=0; i<getRoot().getChildCount(); i++) {
            DefaultMutableTreeNode typeNode = (DefaultMutableTreeNode) getRoot().getChildAt(i);
            if ( hasType(typeNode, type)) {
                for( int j=0; j<typeNode.getChildCount(); j++) {
                    DefaultMutableTreeNode typeChild = (DefaultMutableTreeNode) typeNode.getChildAt(j);
                    if ( !(typeChild.getUserObject() instanceof SchemaItem))
                        continue;
                    SchemaItem childItem = (SchemaItem) typeChild.getUserObject();
                    if ( childItem.getName().equals(item.getName())) {
                        ((DefaultTreeModel) getTree().getModel()).removeNodeFromParent(typeChild);
                        return;
                    }
                }
            }
        }
    }
    
    
    public void addType(DefaultMutableTreeNode type, int position) {
        if( !(type.getUserObject() instanceof SchemaNode) || ((SchemaNode)type.getUserObject()).getNodeType() == null )
            return; // insert type nodes only
        
        ((DefaultTreeModel) getTree().getModel()).insertNodeInto(type, getRoot(), position );
    }
    
    public void addChildToType(DefaultMutableTreeNode parent, final DefaultMutableTreeNode child, final int position) {
        if( !(parent.getUserObject() instanceof SchemaNode) || ((SchemaNode)parent.getUserObject()).getNodeType() == null )
            return; // remove types only
        if ( !(child.getUserObject() instanceof SchemaItem))
            return; // insert schema items only
        
        NodeTypeDefinition type = ((SchemaNode)parent.getUserObject()).getNodeType();
        SchemaItem item = (SchemaItem) child.getUserObject();
        
        for( int i=0; i<getRoot().getChildCount(); i++) {
            DefaultMutableTreeNode typeNode = (DefaultMutableTreeNode) getRoot().getChildAt(i);
            if ( hasType(typeNode, type)) {
                ((DefaultTreeModel) getTree().getModel()).insertNodeInto(child, typeNode, position );
                return;
            }
        }
    }
    
    public static DefaultMutableTreeNode buildTree(NodeTypes types, NodeTypeDefinition[] definitions) {
        // build flat tree
        DefaultMutableTreeNode root = new DefaultMutableTreeNode();
        for( int i=0; i<definitions.length; i++) {
            root.add(setupFlatTree(definitions[i], null, types));
        }
        
        return root;
    }
    
    protected static DefaultMutableTreeNode setupFlatTree( NodeTypeDefinition type, NodeDefinition node, NodeTypes types) {
        DefaultMutableTreeNode parent = new DefaultMutableTreeNode(new SchemaNode(type.getName(),node, type));
        
        PropertyDefinition[] properties = type.getDeclaredPropertyDefinitions();
        for( int i=0; i<properties.length; i++) {
            parent.add(new DefaultMutableTreeNode(new SchemaProperty(properties[i].getName(),properties[i])));
        }
        
        NodeDefinition[] children = type.getDeclaredChildNodeDefinitions();
        for( int i=0; i<children.length; i++) {
            NodeTypeDefinition childType = types.get(children[i].getRequiredPrimaryTypes()[0]);
            if ( childType != null)
                parent.add(new DefaultMutableTreeNode( new SchemaNode(children[i].getName(), children[i], childType)));
        }
        
        return parent;
    }
    
    
}
